-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Allow modification of user vm details if user.vm.readonly.details is empty #10456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## 4.20 #10456 +/- ##
=============================================
- Coverage 16.23% 4.03% -12.21%
=============================================
Files 5657 402 -5255
Lines 498996 32701 -466295
Branches 60566 5826 -54740
=============================================
- Hits 81011 1319 -79692
+ Misses 408951 31227 -377724
+ Partials 9034 155 -8879
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
|
@blueorangutan package |
|
@Pearl1594 a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress. |
|
@Pearl1594 |
Currently when value is null, it picks up the default value, but in this case, we do not want it to use the default value. Unless I understood you wrong @weizhouapache |
Yes, @Pearl1594 , but I think it is still good to use a ConfigKey and let users set it explicitely to "". |
yes. using ConfigKey is more generic, it is easier to support more configurations in the future, for example |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ debian ✔️ suse15. SL-JID 12576 |
engine/schema/src/main/resources/META-INF/db/schema-420to421.sql
Outdated
Show resolved
Hide resolved
a970680 to
dec53f7
Compare
|
|
@Pearl1594 , can you revisit? |
|
Will look into it tomorrow @DaanHoogland . |
dec53f7 to
2e631b5
Compare
|
This pull request has merge conflicts. Dear author, please fix the conflicts and sync your branch with the base branch. |
DaanHoogland
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clgtm, we might want to look at contingency on the number of constructors as well (not in this PR)
|
@blueorangutan package |
|
@Pearl1594 a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16383 |
|
@blueorangutan test |
|
@Pearl1594 a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests |
|
[SF] Trillian Build Failed (tid-15194) |
|
@shwstppr @Pearl1594 , does this still need work? (i.e. the status:needs-work label!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
All 6 test cases passed - empty user.vm.readonly.details now correctly allows users to modify all VM details instead of falling back to default values. LGTM
Test Execution Summary
| Test Case | Description | Status |
|---|---|---|
| TC1 | Default behavior – readonly details blocked for users | PASS |
| TC2 | Empty setting allows all VM detail modifications | PASS |
| TC3 | Custom readonly details are enforced | PASS |
| TC4 | Root Admin can always modify all details | PASS |
| TC5 | Bogus value workaround still works | PASS |
| TC6 | Setting persists after MS restart | PASS |
Detailed Test Report
TC1: Verify default behavior with default setting value
Objective:
Confirm that with default settings, specified VM details (dataDiskController, rootDiskController) remain read-only for non-root users while custom details can be modified.
Test Steps:
- Verified
user.vm.readonly.detailsis set to default value:dataDiskController, rootDiskController - Deployed a VM as regular User (ACSUser account)
- Attempted to modify
dataDiskControllerdetail on the VM - Attempted to modify
rootDiskControllerdetail on the VM - Attempted to add a custom detail
customDetailon the VM
Expected Result:
- Modifications to
dataDiskControllerandrootDiskControllershould be BLOCKED - Modification to custom detail should be ALLOWED
Actual Result:
- Modifications to
dataDiskControllerandrootDiskControllerwere BLOCKED with error 4250 - Custom detail
customDetailwas successfully added ✓
Test Evidence:
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=ide
🙈 Error: (HTTP 530, error code 4250) Internal error executing command, please contact your system administrator
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].rootDiskController=ide
🙈 Error: (HTTP 530, error code 4250) Internal error executing command, please contact your system administrator
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].customDetail=testvalue
{
"virtualmachine": {
"account": "ACSUser",
"affinitygroup": [],
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "0%",
"created": "2026-01-26T07:37:11+0000",
"deleteprotection": false,
"details": {
"customDetail": "testvalue"
},
"diskioread": 0,
"diskiowrite": 0,
"diskkbsread": 0,
"diskkbswrite": 0,
"displayname": "user-vm-1",
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hypervisor": "KVM",
"id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
"ipaddress": "10.1.1.189",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:38:21+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "user-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3757",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "135c61c2-5308-451f-82d1-022cf15e956e",
"ipaddress": "10.1.1.189",
"isdefault": true,
"isolationuri": "vlan://3757",
"macaddress": "02:01:00:cd:00:01",
"netmask": "255.255.255.0",
"networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
"networkname": "user-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"readonlydetails": "dataDiskController, rootDiskController",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
"username": "user",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
Status: PASSED
TC2: Verify empty setting allows all VM detail modifications
Objective:
Core test - verify that clearing the user.vm.readonly.details setting allows regular users to modify all VM details including dataDiskController and rootDiskController.
Test Steps:
- As Root Admin, cleared
user.vm.readonly.detailssetting (set to empty value) - Verified database stores the value
- As regular User (ACSUser), attempted to modify
dataDiskControllerdetail on the VM - As regular User (ACSUser), attempted to modify
rootDiskControllerdetail on the VM
Expected Result:
- Setting should be cleared successfully
- Both
dataDiskControllerandrootDiskControllermodifications should be ALLOWED
Actual Result:
- Setting was cleared successfully (API returns
value: "", DB storesNULL) - Both modifications SUCCEEDED
- Response shows
readonlydetails: ""(empty)
Test Evidence:
- Admin clears the setting
(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=
{
"configuration": {
"category": "Advanced",
"component": "QueryService",
"defaultvalue": "dataDiskController, rootDiskController",
"description": "List of read-only VM settings/details as comma separated string",
"displaytext": "User vm readonly details",
"group": "Compute",
"isdynamic": true,
"name": "user.vm.readonly.details",
"subgroup": "Virtual Machine",
"type": "CSV",
"value": ""
}
}
- Database verification
mysql> SELECT name, value, default_value FROM configuration WHERE name='user.vm.readonly.details';
+--------------------------+-------+----------------------------------------+
| name | value | default_value |
+--------------------------+-------+----------------------------------------+
| user.vm.readonly.details | NULL | dataDiskController, rootDiskController |
+--------------------------+-------+----------------------------------------+
1 row in set (0.00 sec)
- User can now modify previously readonly details
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=ide
{
"virtualmachine": {
"account": "ACSUser",
"affinitygroup": [],
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "11.86%",
"created": "2026-01-26T07:37:11+0000",
"deleteprotection": false,
"details": {
"dataDiskController": "ide"
},
"diskioread": 0,
"diskiowrite": 4,
"diskkbsread": 0,
"diskkbswrite": 24,
"displayname": "user-vm-1",
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hypervisor": "KVM",
"id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
"ipaddress": "10.1.1.189",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:38:21+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "user-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3757",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "135c61c2-5308-451f-82d1-022cf15e956e",
"ipaddress": "10.1.1.189",
"isdefault": true,
"isolationuri": "vlan://3757",
"macaddress": "02:01:00:cd:00:01",
"netmask": "255.255.255.0",
"networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
"networkname": "user-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"readonlydetails": "",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
"username": "user",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].rootDiskController=ide
{
"virtualmachine": {
"account": "ACSUser",
"affinitygroup": [],
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "11.86%",
"created": "2026-01-26T07:37:11+0000",
"deleteprotection": false,
"details": {
"rootDiskController": "ide"
},
"diskioread": 0,
"diskiowrite": 4,
"diskkbsread": 0,
"diskkbswrite": 24,
"displayname": "user-vm-1",
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hypervisor": "KVM",
"id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
"ipaddress": "10.1.1.189",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:38:21+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "user-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3757",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "135c61c2-5308-451f-82d1-022cf15e956e",
"ipaddress": "10.1.1.189",
"isdefault": true,
"isolationuri": "vlan://3757",
"macaddress": "02:01:00:cd:00:01",
"netmask": "255.255.255.0",
"networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
"networkname": "user-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"readonlydetails": "",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
"username": "user",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
Status: PASSED
TC3: Verify custom readonly details are enforced
Objective:
Confirm that custom values in the user.vm.readonly.details setting are properly enforced, blocking those specific details while allowing modification of previously default readonly details.
Test Steps:
- As Root Admin, set
user.vm.readonly.detailsto custom value:customDetail1,customDetail2 - As regular User (ACSUser), attempted to modify
customDetail1on the VM - As regular User (ACSUser), attempted to modify
dataDiskController(previously default readonly, now allowed)
Expected Result:
customDetail1modification should be BLOCKEDdataDiskControllermodification should be ALLOWED
Actual Result:
customDetail1modification was BLOCKED with error 4250dataDiskControllermodification SUCCEEDED- Response shows
readonlydetails: "customDetail1,customDetail2"
Test Evidence:
(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=customDetail1,customDetail2
{
"configuration": {
"category": "Advanced",
"component": "QueryService",
"defaultvalue": "dataDiskController, rootDiskController",
"description": "List of read-only VM settings/details as comma separated string",
"displaytext": "User vm readonly details",
"group": "Compute",
"isdynamic": true,
"name": "user.vm.readonly.details",
"subgroup": "Virtual Machine",
"type": "CSV",
"value": "customDetail1,customDetail2"
}
}
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].customDetail1=test
🙈 Error: (HTTP 530, error code 4250) Internal error executing command, please contact your system administrator
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=virtio
{
"virtualmachine": {
"account": "ACSUser",
"affinitygroup": [],
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "11.77%",
"created": "2026-01-26T07:37:11+0000",
"deleteprotection": false,
"details": {
"dataDiskController": "virtio"
},
"diskioread": 0,
"diskiowrite": 7,
"diskkbsread": 0,
"diskkbswrite": 40,
"displayname": "user-vm-1",
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hypervisor": "KVM",
"id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
"ipaddress": "10.1.1.189",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:38:21+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "user-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3757",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "135c61c2-5308-451f-82d1-022cf15e956e",
"ipaddress": "10.1.1.189",
"isdefault": true,
"isolationuri": "vlan://3757",
"macaddress": "02:01:00:cd:00:01",
"netmask": "255.255.255.0",
"networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
"networkname": "user-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"readonlydetails": "customDetail1,customDetail2",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
"username": "user",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
Status: PASSED
TC4: Verify Root Admin can always modify all details
Objective: Confirm that Root Admin can modify all VM details regardless of the user.vm.readonly.details setting, bypassing readonly restrictions.
Test Steps:
- As Root Admin, set
user.vm.readonly.detailsback to default value:dataDiskController,rootDiskController - As Root Admin, attempted to modify
dataDiskControlleron admin-owned VM - As Root Admin, attempted to modify
rootDiskControlleron admin-owned VM
Expected Result: Both modifications should SUCCEED (Root Admin bypasses readonly restrictions)
Actual Result:
- Both modifications SUCCEEDED
- Root Admin can modify all details regardless of readonly setting
Test Evidence:
(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=dataDiskController,rootDiskController
{
"configuration": {
"category": "Advanced",
"component": "QueryService",
"defaultvalue": "dataDiskController, rootDiskController",
"description": "List of read-only VM settings/details as comma separated string",
"displaytext": "User vm readonly details",
"group": "Compute",
"isdynamic": true,
"name": "user.vm.readonly.details",
"subgroup": "Virtual Machine",
"type": "CSV",
"value": "dataDiskController,rootDiskController"
}
}
(localcloud) 🐱 > update virtualmachine id=5114fc96-b48a-40ab-ae17-dd896de35921 details[0].dataDiskController=virtio
{
"virtualmachine": {
"account": "admin",
"affinitygroup": [],
"arch": "x86_64",
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "11.66%",
"created": "2026-01-26T07:31:57+0000",
"deleteprotection": false,
"details": {
"dataDiskController": "virtio"
},
"diskioread": 0,
"diskiowrite": 4,
"diskkbsread": 0,
"diskkbswrite": 24,
"displayname": "test-vm-1",
"displayvm": true,
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hostid": "f3453c9a-ecf5-45fd-aa3d-dd00554f357a",
"hostname": "ref-trl-10709-k-Mol9-rositsa-kyuchukova-kvm1",
"hypervisor": "KVM",
"id": "5114fc96-b48a-40ab-ae17-dd896de35921",
"instancename": "i-2-4-VM",
"ipaddress": "10.1.1.58",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:33:13+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "test-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3755",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "5e176490-5150-4a73-bae7-6a58cd8e4284",
"ipaddress": "10.1.1.58",
"isdefault": true,
"isolationuri": "vlan://3755",
"macaddress": "02:01:00:cc:00:01",
"netmask": "255.255.255.0",
"networkid": "967e918d-ef94-45f5-9678-650ccedb414f",
"networkname": "test-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "8df43f1b-f87c-11f0-83e5-1e0020000324",
"username": "admin",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
(localcloud) 🐱 > update virtualmachine id=5114fc96-b48a-40ab-ae17-dd896de35921 details[0].rootDiskController=virtio
{
"virtualmachine": {
"account": "admin",
"affinitygroup": [],
"arch": "x86_64",
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "11.66%",
"created": "2026-01-26T07:31:57+0000",
"deleteprotection": false,
"details": {
"rootDiskController": "virtio"
},
"diskioread": 0,
"diskiowrite": 4,
"diskkbsread": 0,
"diskkbswrite": 24,
"displayname": "test-vm-1",
"displayvm": true,
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hostid": "f3453c9a-ecf5-45fd-aa3d-dd00554f357a",
"hostname": "ref-trl-10709-k-Mol9-rositsa-kyuchukova-kvm1",
"hypervisor": "KVM",
"id": "5114fc96-b48a-40ab-ae17-dd896de35921",
"instancename": "i-2-4-VM",
"ipaddress": "10.1.1.58",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:33:13+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "test-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3755",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "5e176490-5150-4a73-bae7-6a58cd8e4284",
"ipaddress": "10.1.1.58",
"isdefault": true,
"isolationuri": "vlan://3755",
"macaddress": "02:01:00:cc:00:01",
"netmask": "255.255.255.0",
"networkid": "967e918d-ef94-45f5-9678-650ccedb414f",
"networkname": "test-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "8df43f1b-f87c-11f0-83e5-1e0020000324",
"username": "admin",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
Status: PASSED
TC5: Verify workaround still works (bogus value)
Objective: Confirm that the existing workaround of setting a bogus/non-existent value in user.vm.readonly.details still functions, allowing users to modify dataDiskController and rootDiskController.
Test Steps:
- As Root Admin, set
user.vm.readonly.detailstobogusNonExistentDetail - As regular User (ACSUser), attempted to modify
dataDiskControlleron the VM - As regular User (ACSUser), attempted to modify
rootDiskControlleron the VM
Expected Result: Both modifications should SUCCEED (bogus value doesn't match real details)
Actual Result:
- Both modifications SUCCEEDED
- Response shows
readonlydetails: "bogusNonExistentDetail"
Test Evidence:
(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=bogusNonExistentDetail
{
"configuration": {
"category": "Advanced",
"component": "QueryService",
"defaultvalue": "dataDiskController, rootDiskController",
"description": "List of read-only VM settings/details as comma separated string",
"displaytext": "User vm readonly details",
"group": "Compute",
"isdynamic": true,
"name": "user.vm.readonly.details",
"subgroup": "Virtual Machine",
"type": "CSV",
"value": "bogusNonExistentDetail"
}
}
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=osdefault
{
"virtualmachine": {
"account": "ACSUser",
"affinitygroup": [],
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "11.81%",
"created": "2026-01-26T07:37:11+0000",
"deleteprotection": false,
"details": {
"dataDiskController": "osdefault"
},
"diskioread": 0,
"diskiowrite": 4,
"diskkbsread": 0,
"diskkbswrite": 24,
"displayname": "user-vm-1",
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hypervisor": "KVM",
"id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
"ipaddress": "10.1.1.189",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:38:21+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "user-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3757",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "135c61c2-5308-451f-82d1-022cf15e956e",
"ipaddress": "10.1.1.189",
"isdefault": true,
"isolationuri": "vlan://3757",
"macaddress": "02:01:00:cd:00:01",
"netmask": "255.255.255.0",
"networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
"networkname": "user-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"readonlydetails": "bogusNonExistentDetail",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
"username": "user",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].rootDiskController=osdefault
{
"virtualmachine": {
"account": "ACSUser",
"affinitygroup": [],
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "11.81%",
"created": "2026-01-26T07:37:11+0000",
"deleteprotection": false,
"details": {
"rootDiskController": "osdefault"
},
"diskioread": 0,
"diskiowrite": 4,
"diskkbsread": 0,
"diskkbswrite": 24,
"displayname": "user-vm-1",
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hypervisor": "KVM",
"id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
"ipaddress": "10.1.1.189",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:38:21+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "user-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3757",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "135c61c2-5308-451f-82d1-022cf15e956e",
"ipaddress": "10.1.1.189",
"isdefault": true,
"isolationuri": "vlan://3757",
"macaddress": "02:01:00:cd:00:01",
"netmask": "255.255.255.0",
"networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
"networkname": "user-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"readonlydetails": "bogusNonExistentDetail",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
"username": "user",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
Status: PASSED
TC6: Verify setting change persists across MS restart
Objective: Confirm that the empty value for user.vm.readonly.details persists after management server restart and the fix continues to work.
Test Steps:
- As Root Admin, set
user.vm.readonly.detailsto empty value - Verified database stores the value (NULL)
- Restarted management server
- Verified MS is running after restart
- Verified setting is still empty via API
- As regular User (ACSUser), attempted to modify
dataDiskControlleron the VM
Expected Result:
- Setting should persist as empty after restart
- VM detail modification should SUCCEED
Actual Result:
- Setting persisted after MS restart
- VM detail modification SUCCEEDED
- Response shows
readonlydetails: ""
Test Evidence:
- Before restart - set empty value
(localcloud) 🐱 > update configuration name=user.vm.readonly.details value=
{
"configuration": {
"category": "Advanced",
"component": "QueryService",
"defaultvalue": "dataDiskController, rootDiskController",
"description": "List of read-only VM settings/details as comma separated string",
"displaytext": "User vm readonly details",
"group": "Compute",
"isdynamic": true,
"name": "user.vm.readonly.details",
"subgroup": "Virtual Machine",
"type": "CSV",
"value": ""
}
}
- Database verification before restart
mysql> SELECT name, value, default_value FROM configuration WHERE name='user.vm.readonly.details';
+--------------------------+-------+----------------------------------------+
| name | value | default_value |
+--------------------------+-------+----------------------------------------+
| user.vm.readonly.details | NULL | dataDiskController, rootDiskController |
+--------------------------+-------+----------------------------------------+
1 row in set (0.00 sec)
- MS restart
[root@ref-trl-10709-k-Mol9-rositsa-kyuchukova-mgmt1 ~]# systemctl restart cloudstack-management && sleep 60 && systemctl status cloudstack-management | head -10
● cloudstack-management.service - CloudStack Management Server
Loaded: loaded (/usr/lib/systemd/system/cloudstack-management.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/cloudstack-management.service.d
└─filelimit.conf
Active: active (running) since Mon 2026-01-26 07:59:08 UTC; 1min 0s ago
Main PID: 210700 (java)
Tasks: 214 (limit: 31170)
Memory: 1.0G
CPU: 1min 17.820s
CGroup: /system.slice/cloudstack-management.service
- After restart - verify setting persists
(localcloud) 🐱 > list configurations name=user.vm.readonly.details
{
"configuration": [
{
"category": "Advanced",
"component": "QueryService",
"defaultvalue": "dataDiskController, rootDiskController",
"description": "List of read-only VM settings/details as comma separated string",
"displaytext": "User vm readonly details",
"group": "Compute",
"isdynamic": true,
"name": "user.vm.readonly.details",
"subgroup": "Virtual Machine",
"type": "CSV"
}
],
"count": 1
}
- User can still modify previously readonly details after restart
(acsuser) 🐱 > update virtualmachine id=2ec715f4-1f7e-480f-a0bf-15dac5036a6c details[0].dataDiskController=scsi
{
"virtualmachine": {
"account": "ACSUser",
"affinitygroup": [],
"cpunumber": 1,
"cpuspeed": 500,
"cpuused": "12.17%",
"created": "2026-01-26T07:37:11+0000",
"deleteprotection": false,
"details": {
"dataDiskController": "scsi"
},
"diskioread": 0,
"diskiowrite": 9,
"diskkbsread": 0,
"diskkbswrite": 56,
"displayname": "user-vm-1",
"domain": "ROOT",
"domainid": "4bd44e93-f87c-11f0-83e5-1e0020000324",
"domainpath": "/",
"guestosid": "4c087596-f87c-11f0-83e5-1e0020000324",
"haenable": false,
"hasannotations": false,
"hostcontrolstate": "Enabled",
"hypervisor": "KVM",
"id": "2ec715f4-1f7e-480f-a0bf-15dac5036a6c",
"ipaddress": "10.1.1.189",
"isdynamicallyscalable": false,
"lastupdated": "2026-01-26T07:38:21+0000",
"memory": 512,
"memoryintfreekbs": -1,
"memorykbs": 524288,
"memorytargetkbs": 524288,
"name": "user-vm-1",
"networkkbsread": 0,
"networkkbswrite": 0,
"nic": [
{
"broadcasturi": "vlan://3757",
"deviceid": "0",
"extradhcpoption": [],
"gateway": "10.1.1.1",
"id": "135c61c2-5308-451f-82d1-022cf15e956e",
"ipaddress": "10.1.1.189",
"isdefault": true,
"isolationuri": "vlan://3757",
"macaddress": "02:01:00:cd:00:01",
"netmask": "255.255.255.0",
"networkid": "d44866b0-6266-4d0c-b1ab-4de49b08287f",
"networkname": "user-network",
"secondaryip": [],
"traffictype": "Guest",
"type": "Isolated"
}
],
"osdisplayname": "CentOS 5.5 (64-bit)",
"ostypeid": "4c087596-f87c-11f0-83e5-1e0020000324",
"passwordenabled": false,
"pooltype": "NetworkFilesystem",
"readonlydetails": "",
"receivedbytes": 0,
"rootdeviceid": 0,
"rootdevicetype": "ROOT",
"securitygroup": [],
"sentbytes": 0,
"serviceofferingid": "78d38968-977a-474e-af16-98dd189339e1",
"serviceofferingname": "Small Instance",
"state": "Running",
"tags": [],
"templatedisplaytext": "CentOS 5.5(64-bit) no GUI (KVM)",
"templateformat": "QCOW2",
"templateid": "4bebd96b-f87c-11f0-83e5-1e0020000324",
"templatename": "CentOS 5.5(64-bit) no GUI (KVM)",
"templatetype": "BUILTIN",
"userid": "9a8d3f9b-1e35-4c92-8e20-7b3696cd6591",
"username": "user",
"zoneid": "13263319-70bf-4290-bddc-9626d00803f6",
"zonename": "ref-trl-10709-k-Mol9-rositsa-kyuchukova"
}
}
Status: PASSED
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes issue #10305 where clearing the user.vm.readonly.details global setting causes it to revert to default values instead of allowing all VM details to be modified. The fix introduces a new optional defaultValueIfEmpty parameter to the ConfigKey class that allows specifying a distinct value when a configuration is explicitly set to empty string, as opposed to being null or using the default value.
Changes:
- Added
defaultValueIfEmptyfield and constructor parameter toConfigKeyclass to handle empty string configurations differently from null/default values - Modified
value()andvalueInScope()methods to check for empty string values and usedefaultValueIfEmptywhen appropriate - Updated
UserVMReadOnlyDetailsConfigKey to use empty string asdefaultValueIfEmpty, allowing users to clear all readonly restrictions
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| framework/config/src/main/java/org/apache/cloudstack/framework/config/ConfigKey.java | Added new field, constructor overload, and logic to handle empty string configurations distinctly from null values |
| api/src/main/java/org/apache/cloudstack/query/QueryService.java | Updated UserVMReadOnlyDetails to pass empty string as defaultValueIfEmpty parameter |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public ConfigKey(Class<T> type, String name, String category, String defaultValue, String description, boolean isDynamic, Scope scope, T multiplier, | ||
| String displayText, String parent, Ternary<String, String, Long> group, Pair<String, Long> subGroup, Kind kind, String options, String defaultValueIfEmpty) { | ||
| this(type, name, category, defaultValue, description, isDynamic, scope, multiplier, displayText, parent, group, subGroup, kind, options); | ||
| this._defaultValueIfEmpty = defaultValueIfEmpty; | ||
| } |
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding JavaDoc documentation for this new constructor to explain the purpose and usage of the defaultValueIfEmpty parameter. This would help other developers understand when and why to use this constructor variant.
| T _value = null; | ||
|
|
||
| static ConfigDepotImpl s_depot = null; | ||
|
|
Copilot
AI
Jan 26, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding JavaDoc documentation for the new _defaultValueIfEmpty field to explain its purpose. This field represents the value to use when the configuration is explicitly set to empty string, as opposed to using the default value. This distinction is important for understanding the behavior when users clear a configuration value.
| /** | |
| * Alternative default value used when the configuration value is explicitly set | |
| * to the empty string. This allows distinguishing between: | |
| * <ul> | |
| * <li>a missing or unset configuration value, which uses {@link #_defaultValue}, and</li> | |
| * <li>a configuration value explicitly cleared to "", which uses this value instead.</li> | |
| * </ul> | |
| */ |
* 4.22: fix install path for systemvm templates when introducing new sec storage (#11605) fix Sensitive Data Exposure Through Exception Logging in OVM Hypervis… (#12032) Fix snapshot physical size after migration (#12166) ConfigDrive: use file absolute path instead of canonical path to create ISO (#11623) Add log for null templateVO (#12406) snapshot: fix listSnapshots for volume which got delete and whose storage pool got deleted (#12433) Notify user if template upgrade is not required (#12483) Fix: proper permissions for systemvm template registrations on hardened systems (#12098) Allow modification of user vm details if user.vm.readonly.details is empty (#10456) NPE fix while deleting storage pool when pool has detached volumes (#12451)



Description
This PR fixes: #10305
Currently when the global setting 'user.vm.readonly.details' is cleared, it sets the global setting value to NULL. Querying a global setting whose value is null returns the default value. Hence, updating this specific global setting value to "" as opposed to NULL.
Types of changes
Feature/Enhancement Scale or Bug Severity
Feature/Enhancement Scale
Bug Severity
Screenshots (if appropriate):
How Has This Been Tested?
How did you try to break this feature and the system with this change?